#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion

namespace SkyBurner
{
    #region SkyBurnerBulletBase class
    public class SkyBurnerBulletBase : SkyBurnerWorldObject
    {
        #region protected attributes
        protected Vector3 m_vDirection;
        protected float m_fSpeed;
        protected float m_fLifeTime;
        protected float m_fDamage;
        protected BoundingSphere m_boundingSphere;
        #endregion

        #region Properties
        public bool Alive
        {
            get { return (m_fLifeTime > 0.0f); }
        }

        public BoundingSphere BoundingSphere
        {
            get { return m_boundingSphere; }
        }

        public float Damage
        {
            get { return m_fDamage; }
        }
        #endregion

        public SkyBurnerBulletBase(BaseGame pGame, SkyBurnerWorld pSkyBurnerWorld, Vector3 vPosition, Vector3 vDirection, float fSpeed, float fLifeTime, float fDamage, float pBoundingSphereRadius)
            : base(pGame, pSkyBurnerWorld)
        {
            m_vPosition = vPosition;
            m_vDirection = vDirection;
            m_fSpeed = fSpeed;
            m_fLifeTime = fLifeTime;
            m_fDamage = fDamage;
            m_boundingSphere = new BoundingSphere(m_vPosition, pBoundingSphereRadius);

            m_vDirection.Normalize();
        }

        public override void Update(GameTime gameTime, Camera pActiveCamera)
        {
            m_fLifeTime -= gameTime.ElapsedGameTime.Milliseconds;
            m_vPosition += m_vDirection * (m_fSpeed * gameTime.ElapsedGameTime.Milliseconds);
            m_boundingSphere.Center = m_vPosition;
        }

        public virtual void OnDead()
        {

        }
    }
    #endregion

    #region SkyBurnerBulletParticle class
    public class SkyBurnerBulletParticle : SkyBurnerBulletBase
    {
        protected ParticleEmitterBase m_particleEmitter;

        public SkyBurnerBulletParticle(BaseGame pGame, SkyBurnerWorld pSkyBurnerWorld, Vector3 vPosition, Vector3 vDirection, float fSpeed, float fLifeTime, float fDamage, float pBoundingSphereRadius, ParticleEmitterBase pParticleEmitter)
            : base(pGame, pSkyBurnerWorld, vPosition, vDirection, fSpeed, fLifeTime, fDamage, pBoundingSphereRadius)
        {
            m_particleEmitter = pParticleEmitter;
            m_particleEmitter.Position = vPosition;           
        }

        public override void Update(GameTime gameTime, Camera pActiveCamera)
        {
            base.Update(gameTime, pActiveCamera);

            if (m_fLifeTime > 0.0f)
                m_particleEmitter.Position = m_vPosition;
        }

        public override void OnDead()
        {
            base.OnDead();
            m_particleEmitter.Active = false;
        }
    }
    #endregion

    #region SkyBurnerBulletSprite class
    public class SkyBurnerBulletSprite : SkyBurnerBulletBase
    {
        static protected MOODModel m_moodSprite;
        static protected Effect m_spriteShader;
        protected Texture2D m_spriteTexture;
        protected Vector3 m_spriteColor;
        protected Vector3 m_positionOffset;

        public SkyBurnerBulletSprite(BaseGame pGame, SkyBurnerWorld pSkyBurnerWorld, Texture2D pSpriteTexture, Vector3 vPosition, Vector3 vDirection, float fSpeed, float fLifeTime, float fDamage, float pBoundingSphereRadius, Vector3 pColor)
            : base(pGame, pSkyBurnerWorld, vPosition, vDirection, fSpeed, fLifeTime, fDamage, pBoundingSphereRadius)
        {
            if (m_moodSprite == null)
            {
                // initialize bullet sprite shader...
                m_spriteShader = m_Game.ContentManager.Load<Effect>("Data\\Shaders\\BulletSprite");
                //m_spriteTexture = m_Game.ContentManager.Load<Texture2D>("Data\\Textures\\bullet_sprite");

                // initialize quad model...
                m_moodSprite = new MOODModel(pGame, "Data\\Models\\sprite.mood");

            }
            
            // center billboard model...
            m_positionOffset.X = -pBoundingSphereRadius * 0.5f;
            m_positionOffset.Y = -pBoundingSphereRadius * 0.5f;

            m_spriteColor = pColor;
            m_spriteTexture = pSpriteTexture;
        }

        public override void Update(GameTime gameTime, Camera pActiveCamera)
        {
            base.Update(gameTime, pActiveCamera);

            m_mxWorld = Matrix.CreateScale(m_boundingSphere.Radius) * Matrix.CreateBillboard(m_vPosition + m_positionOffset, pActiveCamera.Position, pActiveCamera.Up, pActiveCamera.View);// *Matrix.CreateTranslation(m_vPosition);
            m_mxView = Matrix.CreateLookAt(pActiveCamera.Position, pActiveCamera.LookAt, pActiveCamera.Up);
            m_mxProjection = Matrix.CreatePerspectiveFieldOfView(pActiveCamera.FOV, pActiveCamera.AspectRatio, pActiveCamera.NearPlane, pActiveCamera.FarPlane);            
        }

        public override void Draw(GameTime gameTime, Camera pActiveCamera)
        {
            base.Draw(gameTime, pActiveCamera);

            m_Game.GraphicsDevice.RenderState.CullMode = CullMode.None;

            m_Game.GraphicsDevice.RenderState.AlphaBlendEnable = true;
            m_Game.GraphicsDevice.RenderState.AlphaBlendOperation = BlendFunction.Add;
            m_Game.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
            m_Game.GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
            
            //m_Game.GraphicsDevice.RenderState.AlphaFunction = CompareFunction.Greater;
            //m_Game.GraphicsDevice.RenderState.ReferenceAlpha = 0x80;

            m_spriteShader.Parameters["World"].SetValue(m_mxWorld);
            m_spriteShader.Parameters["View"].SetValue(m_mxView);
            m_spriteShader.Parameters["Projection"].SetValue(m_mxProjection);
            m_spriteShader.Parameters["SpriteTexture"].SetValue(m_spriteTexture);
            m_spriteShader.Parameters["SpriteColor"].SetValue(m_spriteColor);

            foreach (MOODGroup moodGroup in m_moodSprite.Groups)
            {
                if (moodGroup.TriangleCount <= 0)
                    continue;

                m_Game.GraphicsDevice.VertexDeclaration = moodGroup.VertexDecl;

                m_spriteShader.Begin();
                foreach (EffectPass pass in m_spriteShader.CurrentTechnique.Passes)
                {
                    pass.Begin();
                    m_Game.GraphicsDevice.Vertices[0].SetSource(moodGroup.VertexBuffer, 0, VertexPositionNormalTexture.SizeInBytes);
                    m_Game.GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, moodGroup.TriangleCount);
                    pass.End();
                }
                m_spriteShader.End();
            }
            m_Game.GraphicsDevice.RenderState.AlphaBlendEnable = false;
        }
    }
    #endregion

    #region RocketBullet class
    public class SkyBurnerRocketBullet : SkyBurnerBulletParticle
    {
        static protected MOODModel m_rocketModel;
        static protected MOODBlinnPhongShader m_moodBlinnPhongShader;
        protected Matrix m_mxRocketTransformation;
        protected Vector3 m_vSunLightPosition;

        public SkyBurnerRocketBullet(BaseGame pGame, SkyBurnerWorld pSkyBurnerWorld, Vector3 pSunLightPosition, Matrix pRocketTransformation, Vector3 vPosition, Vector3 vDirection, float fSpeed, float fLifeTime, float fDamage, float pBoundingSphereRadius, ParticleEmitterBase pParticleEmitter)
            : base(pGame, pSkyBurnerWorld, vPosition, vDirection, fSpeed, fLifeTime, fDamage, pBoundingSphereRadius, pParticleEmitter)
        {
            if ( m_rocketModel == null )
                m_rocketModel = new MOODModel(pGame, "Data\\Models\\rocket2.mood");

            if (m_moodBlinnPhongShader == null)
                m_moodBlinnPhongShader = (MOODBlinnPhongShader)m_Game.ShadersManager.GetShader("BlinnPhongShader");

            m_mxRocketTransformation = pRocketTransformation;
            m_vSunLightPosition = pSunLightPosition;
        }

        public override void Update(GameTime gameTime, Camera pActiveCamera)
        {
            base.Update(gameTime, pActiveCamera);
        }

        public override void Draw(GameTime gameTime, Camera pActiveCamera)
        {
            base.Draw(gameTime, pActiveCamera);

            m_rocketModel.WorldMatrix = m_mxRocketTransformation * Matrix.CreateTranslation(m_vPosition);
            m_rocketModel.ViewMatrix = Matrix.CreateLookAt(pActiveCamera.Position, pActiveCamera.LookAt, pActiveCamera.Up);
            m_rocketModel.ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(pActiveCamera.FOV, pActiveCamera.AspectRatio, pActiveCamera.NearPlane, pActiveCamera.FarPlane);

            m_moodBlinnPhongShader.Draw(gameTime, pActiveCamera, pActiveCamera.Position, m_vPosition + m_vSunLightPosition, m_rocketModel);
        }

        public override void OnDead()
        {
            base.OnDead();

#if OLD_PARTICLE
            // spawn explosion...
            ParticleEmitterRocketExplosion rocketExplosionEmitter = new ParticleEmitterRocketExplosion(m_Game);

            rocketExplosionEmitter.Position = m_vPosition;
            rocketExplosionEmitter.ParticleTexture = m_Game.ContentManager.Load<Texture2D>("Data\\Textures\\smoke1");
            rocketExplosionEmitter.ParticleLife = 2500.0f;
            rocketExplosionEmitter.ParticleSize = 15.0f;
            rocketExplosionEmitter.ParticleSpeed = 10.0f;
            rocketExplosionEmitter.ParticleEmitInterval = 0.0f;
            rocketExplosionEmitter.MaxParticleCount = 150;
            rocketExplosionEmitter.Life = 5000.0f;

            m_skyBurnerWorld.ParticleSystemManager.AddParticleEmitter(rocketExplosionEmitter);
#endif
            m_Game.SoundManager.PlaySound("Explosion3");
        }
    }
    #endregion

    #region RocketBulletPlayerTarget class
    public class SkyBurnerRocketBulletPlayerTarget : SkyBurnerBulletParticle
    {
        static protected MOODModel m_rocketModel;
        static protected MOODBlinnPhongShader m_moodBlinnPhongShader;
        private Vector3 m_vLastPlayerPosition;
        private float m_fLastTickMove;
        private float m_fTargetTime;
        protected Matrix m_mxRocketTransformation;
        protected Vector3 m_vSunLightPosition;

        public SkyBurnerRocketBulletPlayerTarget(BaseGame pGame, SkyBurnerWorld pSkyBurnerWorld, Vector3 pSunLightPosition, Matrix pRocketTransformation, Vector3 vPosition, Vector3 vDirection, float fSpeed, float fLifeTime, float fDamage, float pBoundingSphereRadius, ParticleEmitterBase pParticleEmitter)
            : base(pGame, pSkyBurnerWorld, vPosition, vDirection, fSpeed, fLifeTime, fDamage, pBoundingSphereRadius, pParticleEmitter)
        {
            if (m_rocketModel == null)
                m_rocketModel = new MOODModel(pGame, "Data\\Models\\rocket2.mood");

            if (m_moodBlinnPhongShader == null)
                m_moodBlinnPhongShader = (MOODBlinnPhongShader)m_Game.ShadersManager.GetShader("BlinnPhongShader");

            m_fTargetTime = 1000.0f;
            m_mxRocketTransformation = pRocketTransformation;
            m_vSunLightPosition = pSunLightPosition;
        }

        public override void Update(GameTime gameTime, Camera pActiveCamera)
        {
            if (m_fTargetTime > 0.0f)
            {
                m_vLastPlayerPosition = m_skyBurnerWorld.Player.Position;
                m_fLastTickMove = (float)gameTime.TotalGameTime.TotalMilliseconds;

                m_vDirection = m_vLastPlayerPosition - m_vPosition;
                m_vDirection.Normalize();
            }
            m_fTargetTime -= (float)gameTime.ElapsedGameTime.Milliseconds;
            
            base.Update(gameTime, pActiveCamera);
        }

        public override void Draw(GameTime gameTime, Camera pActiveCamera)
        {
            base.Draw(gameTime, pActiveCamera);

            m_rocketModel.WorldMatrix = m_mxRocketTransformation * Matrix.CreateTranslation(m_vPosition);
            m_rocketModel.ViewMatrix = Matrix.CreateLookAt(pActiveCamera.Position, pActiveCamera.LookAt, pActiveCamera.Up);
            m_rocketModel.ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(pActiveCamera.FOV, pActiveCamera.AspectRatio, pActiveCamera.NearPlane, pActiveCamera.FarPlane);

            m_moodBlinnPhongShader.Draw(gameTime, pActiveCamera, pActiveCamera.Position, m_vPosition + m_vSunLightPosition, m_rocketModel);
        }

        public override void OnDead()
        {
            base.OnDead();

#if OLD_PARTICLE
            // spawn explosion...
            ParticleEmitterRocketExplosion rocketExplosionEmitter = new ParticleEmitterRocketExplosion(m_Game);

            rocketExplosionEmitter.Position = m_vPosition;
            rocketExplosionEmitter.ParticleTexture = m_Game.ContentManager.Load<Texture2D>("Data\\Textures\\smoke1");
            rocketExplosionEmitter.ParticleLife = 2500.0f;
            rocketExplosionEmitter.ParticleSize = 1.0f;
            rocketExplosionEmitter.ParticleSpeed = 10.0f;
            rocketExplosionEmitter.ParticleEmitInterval = 0.0f;
            rocketExplosionEmitter.MaxParticleCount = 150;
            rocketExplosionEmitter.Life = 5000.0f;

            m_skyBurnerWorld.ParticleSystemManager.AddParticleEmitter(rocketExplosionEmitter);
#endif
            m_Game.SoundManager.PlaySound("Explosion3");
        }
    }
    #endregion

}
